package edu.nf.ch13.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * @author wangl
 * @date 2025/5/6
 * 切面类，使用@Aspect注解标识
 */
@Aspect
@Component
public class UserServiceAspect {

    /**
     * 使用@Pointcut注解标识在一个任意的方法上表示未切入点，
     * 主要是来编写切入点表达式（AspectJ的切入点表达式）。
     * execution()是用来执行切入点表达式的一个函数
     * 下面的表达式中：
     * 第一个星号：表示连接点方法的访问修饰符
     * 第二个星号：表示所有类
     * 第三个星号：表示类下面的所有方法
     * （星号可以改为具体的类名或者方法名）
     * （..）表示任意类型和个数的参数
     *
     * 因此，被切入点表达式找到的这些方法都称之为连接点
     */
    @Pointcut("execution(* edu.nf.ch13.service.UserService.*(..))")
    public void pointcut() {
    }

    /**
     * 前置通知
     * @param jp 连接点信息（目标方法的信息）
     */
    @Before("pointcut()")
    public void before(JoinPoint jp) {
        System.out.println("前置通知，参数：" + jp.getArgs()[0]);
    }

    /**
     * 后置通知
     * @param jp 连接点信息
     * @param returnVal 连接点方法的返回值
     */
    @AfterReturning(value = "pointcut()", returning = "returnVal")
    public Object after(JoinPoint jp, String returnVal) {
        System.out.println("后置通知，返回值：" + returnVal);
        return returnVal;
    }

    /**
     * 环绕通知
     * @param jp 连接点信息
     */
    @Around("pointcut()")
    public Object around(ProceedingJoinPoint jp) throws Throwable {
        System.out.println("环绕通知前...");
        //调用目标方法
        Object returnVal = jp.proceed();
        System.out.println("环绕通知后...");
        return returnVal;
    }

    /**
     * 异常通知
     * @param jp 连接点信息
     * @param e 连接点方法产生的异常对象
     */
    @AfterThrowing(value = "pointcut()", throwing = "e")
    public void afterThrowing(JoinPoint jp, Exception e) {
        System.out.println("异常通知，异常：" + e.getMessage());
    }

    /**
     * 最终通知
     * @param jp 连接点信息
     */
    @After("pointcut()")
    public void after(JoinPoint jp) {
        System.out.println("最终通知");
    }

}